home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 45
/
Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso
/
Aminet
/
gfx
/
x11
/
x3270_3_2_16.lha
/
amiga_src
/
kybd.c
< prev
next >
Wrap
C/C++ Source or Header
|
2009-02-26
|
70KB
|
3,239 lines
/*
* Modifications Copyright 1993, 1994, 1995, 1996, 1999, 2000 by Paul Mattes.
* Original X11 Port Copyright 1990 by Jeff Sparkes.
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
* All Rights Reserved. GTRC hereby grants public use of this software.
* Derivative works based on this software must incorporate this copyright
* notice.
*/
/*
* kybd.c
* This module handles the keyboard for the 3270 emulator.
*/
#include "globals.h"
#if defined(X3270_DISPLAY) /*[*/
#include <X11/Xatom.h>
#endif
#define XK_3270
#if defined(X3270_APL) /*[*/
#define XK_APL
#endif /*]*/
#include <X11/keysym.h>
#include <fcntl.h>
#include "3270ds.h"
#include "appres.h"
#include "ctlr.h"
#include "cg.h"
#include "resources.h"
#include "actionsc.h"
#include "ansic.h"
#include "aplc.h"
#include "ctlrc.h"
#include "ftc.h"
#include "hostc.h"
#include "keymapc.h"
#include "keypadc.h"
#include "kybdc.h"
#include "macrosc.h"
#include "popupsc.h"
#include "printc.h"
#include "screenc.h"
#if defined(X3270_DISPLAY) /*[*/
#include "selectc.h"
#endif /*]*/
#include "statusc.h"
#include "tablesc.h"
#include "telnetc.h"
#include "togglesc.h"
#include "trace_dsc.h"
#include "utilc.h"
/* Statics */
static enum { NONE, COMPOSE, FIRST } composing = NONE;
static unsigned char pf_xlate[] = {
AID_PF1, AID_PF2, AID_PF3, AID_PF4, AID_PF5, AID_PF6,
AID_PF7, AID_PF8, AID_PF9, AID_PF10, AID_PF11, AID_PF12,
AID_PF13, AID_PF14, AID_PF15, AID_PF16, AID_PF17, AID_PF18,
AID_PF19, AID_PF20, AID_PF21, AID_PF22, AID_PF23, AID_PF24
};
static unsigned char pa_xlate[] = {
AID_PA1, AID_PA2, AID_PA3
};
#define PF_SZ (sizeof(pf_xlate)/sizeof(pf_xlate[0]))
#define PA_SZ (sizeof(pa_xlate)/sizeof(pa_xlate[0]))
static unsigned long unlock_id;
#define UNLOCK_MS 350
static Boolean key_Character(int cgcode, Boolean with_ge, Boolean pasting);
static Boolean flush_ta(void);
static void key_AID(unsigned char aid_code);
static void kybdlock_set(unsigned int bits, const char *cause);
static KeySym MyStringToKeysym(char *s, enum keytype *keytypep);
static int nxk = 0;
static struct xks {
KeySym key;
KeySym assoc;
} *xk;
static Boolean insert = False; /* insert mode */
static Boolean reverse = False; /* reverse-input mode */
/* Globals */
unsigned int kybdlock = KL_NOT_CONNECTED;
unsigned char aid = AID_NO; /* current attention ID */
/* Composite key mappings. */
struct akeysym {
KeySym keysym;
enum keytype keytype;
};
static struct akeysym cc_first;
static struct composite {
struct akeysym k1, k2;
struct akeysym translation;
} *composites = NULL;
static int n_composites = 0;
#define ak_eq(k1, k2) (((k1).keysym == (k2).keysym) && \
((k1).keytype == (k2).keytype))
static struct ta {
struct ta *next;
XtActionProc fn;
char *parm1;
char *parm2;
} *ta_head = (struct ta *) NULL,
*ta_tail = (struct ta *) NULL;
static char dxl[] = "0123456789abcdef";
#define FROM_HEX(c) (strchr(dxl, tolower(c)) - dxl)
extern Widget *screen;
/*
* Put an action on the typeahead queue.
*/
static void
enq_ta(XtActionProc fn, char *parm1, char *parm2)
{
struct ta *ta;
/* If no connection, forget it. */
if (!CONNECTED) {
trace_event(" dropped (not connected)\n");
return;
}
/* If operator error, complain and drop it. */
if (kybdlock & KL_OERR_MASK) {
ring_bell();
trace_event(" dropped (operator error)\n");
return;
}
/* If scroll lock, complain and drop it. */
if (kybdlock & KL_SCROLLED) {
ring_bell();
trace_event(" dropped (scrolled)\n");
return;
}
/* If typeahead disabled, complain and drop it. */
if (!appres.typeahead) {
trace_event(" dropped (no typeahead)\n");
return;
}
ta = (struct ta *) Malloc(sizeof(*ta));
ta->next = (struct ta *) NULL;
ta->fn = fn;
ta->parm1 = ta->parm2 = CN;
if (parm1) {
ta->parm1 = NewString(parm1);
if (parm2)
ta->parm2 = NewString(parm2);
}
if (ta_head)
ta_tail->next = ta;
else {
ta_head = ta;
status_typeahead(True);
}
ta_tail = ta;
trace_event(" action queued (kybdlock 0x%x)\n", kybdlock);
}
/*
* Execute an action from the typeahead queue.
*/
Boolean
run_ta(void)
{
struct ta *ta;
if (kybdlock || (ta = ta_head) == (struct ta *)NULL)
return False;
if ((ta_head = ta->next) == (struct ta *)NULL) {
ta_tail = (struct ta *)NULL;
status_typeahead(False);
}
action_internal(ta->fn, IA_TYPEAHEAD, ta->parm1, ta->parm2);
if (ta->parm1 != CN)
Free(ta->parm1);
if (ta->parm2 != CN)
Free(ta->parm2);
Free(ta);
return True;
}
/*
* Flush the typeahead queue.
* Returns whether or not anything was flushed.
*/
static Boolean
flush_ta(void)
{
struct ta *ta, *next;
Boolean any = False;
for (ta = ta_head; ta != (struct ta *) NULL; ta = next) {
if (ta->parm1)
Free(ta->parm1);
if (ta->parm2)
Free(ta->parm2);
next = ta->next;
Free(ta);
any = True;
}
ta_head = ta_tail = (struct ta *) NULL;
status_typeahead(False);
return any;
}
/* Set bits in the keyboard lock. */
static void
kybdlock_set(unsigned int bits, const char *cause unused)
{
unsigned int n;
n = kybdlock | bits;
if (n != kybdlock) {
#if defined(KYBDLOCK_TRACE) /*[*/
trace_event(" %s: kybdlock |= 0x%04x, 0x%04x -> 0x%04x\n",
cause, bits, kybdlock, n);
#endif /*]*/
kybdlock = n;
status_kybdlock();
}
}
/* Clear bits in the keyboard lock. */
void
kybdlock_clr(unsigned int bits, const char *cause unused)
{
unsigned int n;
n = kybdlock & ~bits;
if (n != kybdlock) {
#if defined(KYBDLOCK_TRACE) /*[*/
trace_event(" %s: kybdlock &= ~0x%04x, 0x%04x -> 0x%04x\n",
cause, bits, kybdlock, n);
#endif /*]*/
kybdlock = n;
status_kybdlock();
}
}
/*
* Set or clear enter-inhibit mode.
*/
void
kybd_inhibit(Boolean inhibit)
{
if (inhibit) {
kybdlock_set(KL_ENTER_INHIBIT, "kybd_inhibit");
if (kybdlock == KL_ENTER_INHIBIT)
status_reset();
} else {
kybdlock_clr(KL_ENTER_INHIBIT, "kybd_inhibit");
if (!kybdlock)
status_reset();
}
}
/*
* Called when a host connects or disconnects.
*/
static void
kybd_connect(Boolean connected)
{
if (kybdlock & KL_DEFERRED_UNLOCK)
RemoveTimeOut(unlock_id);
kybdlock_clr(-1, "kybd_connect");
if (connected) {
/* Wait for any output or a WCC(restore) from the host */
kybdlock_set(KL_AWAITING_FIRST, "kybd_connect");
} else {
kybdlock_set(KL_NOT_CONNECTED, "kybd_connect");
(void) flush_ta();
}
}
/*
* Called when we switch between 3270 and ANSI modes.
*/
static void
kybd_in3270(Boolean in3270 unused)
{
if (kybdlock & KL_DEFERRED_UNLOCK)
RemoveTimeOut(unlock_id);
kybdlock_clr(-1, "kybd_connect");
}
/*
* Called to initialize the keyboard logic.
*/
void
kybd_init(void)
{
/* Register interest in connect and disconnect events. */
register_schange(ST_CONNECT, kybd_connect);
register_schange(ST_3270_MODE, kybd_in3270);
}
/*
* Toggle insert mode.
*/
static void
insert_mode(Boolean on)
{
insert = on;
status_insert_mode(on);
}
/*
* Toggle reverse mode.
*/
static void
reverse_mode(Boolean on)
{
reverse = on;
status_reverse_mode(on);
}
/*
* Lock the keyboard because of an operator error.
*/
static void
operator_error(int error_type)
{
if (sms_redirect())
popup_an_error("Keyboard locked");
if (appres.oerr_lock || sms_redirect()) {
status_oerr(error_type);
mcursor_locked();
kybdlock_set((unsigned int)error_type, "operator_error");
(void) flush_ta();
} else {
ring_bell();
}
}
/*
* Handle an AID (Attention IDentifier) key. This is the common stuff that
* gets executed for all AID keys (PFs, PAs, Clear and etc).
*/
static void
key_AID(unsigned char aid_code)
{
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
register unsigned i;
if (aid_code == AID_ENTER) {
net_sendc('\r');
return;
}
for (i = 0; i < PF_SZ; i++)
if (aid_code == pf_xlate[i]) {
ansi_send_pf(i+1);
return;
}
for (i = 0; i < PA_SZ; i++)
if (aid_code == pa_xlate[i]) {
ansi_send_pa(i+1);
return;
}
return;
}
#endif /*]*/
if (IN_SSCP) {
if (kybdlock & KL_OIA_MINUS)
return;
if (aid_code != AID_ENTER && aid_code != AID_CLEAR) {
status_minus();
kybdlock_set(KL_OIA_MINUS, "key_AID");
return;
}
}
if (IN_SSCP && aid_code == AID_ENTER) {
/* Act as if the host had written our input. */
buffer_addr = cursor_addr;
}
if (!IN_SSCP || aid_code != AID_CLEAR) {
status_twait();
mcursor_waiting();
insert_mode(False);
kybdlock_set(KL_OIA_TWAIT | KL_OIA_LOCKED, "key_AID");
}
aid = aid_code;
ctlr_read_modified(aid, False);
if (!IN_SSCP) {
ticking_start(False);
status_ctlr_done();
}
}
void
PF_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
unsigned k;
action_debug(PF_action, event, params, num_params);
if (check_usage(PF_action, *num_params, 1, 1) < 0)
return;
k = atoi(params[0]);
if (k < 1 || k > PF_SZ) {
popup_an_error("%s: Invalid argument '%s'",
action_name(PF_action), params[0]);
return;
}
if (kybdlock & KL_OIA_MINUS)
return;
else if (kybdlock)
enq_ta(PF_action, params[0], CN);
else
key_AID(pf_xlate[k-1]);
}
void
PA_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
unsigned k;
action_debug(PA_action, event, params, num_params);
if (check_usage(PA_action, *num_params, 1, 1) < 0)
return;
k = atoi(params[0]);
if (k < 1 || k > PA_SZ) {
popup_an_error("%s: Invalid argument '%s'",
action_name(PA_action), params[0]);
return;
}
if (kybdlock & KL_OIA_MINUS)
return;
else if (kybdlock)
enq_ta(PA_action, params[0], CN);
else
key_AID(pa_xlate[k-1]);
}
/*
* ATTN key, per RFC 2355. Sends IP, regardless.
*/
void
Attn_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Attn_action, event, params, num_params);
if (!IN_3270)
return;
net_interrupt();
}
/*
* IAC IP, which works for 5250 System Request and interrupts the program
* on an AS/400, even when the keyboard is locked.
*
* This is now the same as the Attn action.
*/
void
Interrupt_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Interrupt_action, event, params, num_params);
if (!IN_3270)
return;
net_interrupt();
}
#define GE_WFLAG 0x100
#define PASTE_WFLAG 0x200
static void
key_Character_wrapper(Widget w unused, XEvent *event unused, String *params,
Cardinal *num_params unused)
{
int cgcode;
Boolean with_ge = False;
Boolean pasting = False;
cgcode = atoi(params[0]);
if (cgcode & GE_WFLAG) {
with_ge = True;
cgcode &= ~GE_WFLAG;
}
if (cgcode & PASTE_WFLAG) {
pasting = True;
cgcode &= ~PASTE_WFLAG;
}
trace_event(" %s -> Key(%s\"%s\")\n",
ia_name[(int) ia_cause],
with_ge ? "GE " : "",
ctl_see((int) cg2asc[cgcode]));
(void) key_Character(cgcode, with_ge, pasting);
}
/*
* Handle an ordinary displayable character key. Lots of stuff to handle
* insert-mode, protected fields and etc.
*/
static Boolean
key_Character(int cgcode, Boolean with_ge, Boolean pasting)
{
register int baddr, end_baddr;
register unsigned char *fa;
Boolean no_room = False;
if (kybdlock) {
char code[64];
(void) sprintf(code, "%d", cgcode |
(with_ge ? GE_WFLAG : 0) |
(pasting ? PASTE_WFLAG : 0));
enq_ta(key_Character_wrapper, code, CN);
return False;
}
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (IS_FA(screen_buf[baddr]) || FA_IS_PROTECTED(*fa)) {
operator_error(KL_OERR_PROTECTED);
return False;
}
if (appres.numeric_lock && FA_IS_NUMERIC(*fa) &&
!((cgcode >= CG_0 && cgcode <= CG_9) ||
cgcode == CG_minus || cgcode == CG_period)) {
operator_error(KL_OERR_NUMERIC);
return False;
}
if (reverse || (insert && screen_buf[baddr])) {
int last_blank = -1;
/* Find next null, next fa, or last blank */
end_baddr = baddr;
if (screen_buf[end_baddr] == CG_space)
last_blank = end_baddr;
do {
INC_BA(end_baddr);
if (screen_buf[end_baddr] == CG_space)
last_blank = end_baddr;
if (screen_buf[end_baddr] == CG_null
|| IS_FA(screen_buf[end_baddr]))
break;
} while (end_baddr != baddr);
/* Pretend a trailing blank is a null, if desired. */
if (toggled(BLANK_FILL) && last_blank != -1) {
INC_BA(last_blank);
if (last_blank == end_baddr) {
DEC_BA(end_baddr);
ctlr_add(end_baddr, CG_null, 0);
}
}
/* Check for field overflow. */
if (screen_buf[end_baddr] != CG_null) {
if (insert) {
operator_error(KL_OERR_OVERFLOW);
return False;
} else { /* reverse */
no_room = True;
}
} else {
/* Shift data over. */
if (end_baddr > baddr) {
/* At least one byte to copy, no wrap. */
ctlr_bcopy(baddr, baddr+1, end_baddr - baddr,
0);
} else if (end_baddr < baddr) {
/* At least one byte to copy, wraps to top. */
ctlr_bcopy(0, 1, end_baddr, 0);
ctlr_add(0, screen_buf[(ROWS * COLS) - 1], 0);
ctlr_bcopy(baddr, baddr+1,
((ROWS * COLS) - 1) - baddr, 0);
}
}
}
/* Replace leading nulls with blanks, if desired. */
if (formatted && toggled(BLANK_FILL)) {
int baddr_sof = fa - screen_buf;
register int baddr_fill = baddr;
DEC_BA(baddr_fill);
while (baddr_fill != baddr_sof) {
/* Check for backward line wrap. */
if ((baddr_fill % COLS) == COLS - 1) {
Boolean aborted = True;
register int baddr_scan = baddr_fill;
/*
* Check the field within the preceeding line
* for NULLs.
*/
while (baddr_scan != baddr_sof) {
if (screen_buf[baddr_scan] != CG_null) {
aborted = False;
break;
}
if (!(baddr_scan % COLS))
break;
DEC_BA(baddr_scan);
}
if (aborted)
break;
}
if (screen_buf[baddr_fill] == CG_null)
ctlr_add(baddr_fill, CG_space, 0);
DEC_BA(baddr_fill);
}
}
/* Add the character. */
if (no_room) {
do {
INC_BA(baddr);
} while (!IS_FA(screen_buf[baddr]));
} else {
ctlr_add(baddr, (unsigned char)cgcode,
(unsigned char)(with_ge ? CS_GE : 0));
ctlr_add_fg(baddr, 0);
ctlr_add_gr(baddr, 0);
if (!reverse)
INC_BA(baddr);
}
/*
* Implement auto-skip, and don't land on attribute bytes.
* This happens for all pasted data (even DUP), and for all
* keyboard-generated data except DUP.
*/
if (pasting || (cgcode != CG_dup)) {
if (IS_FA(screen_buf[baddr]) &&
FA_IS_SKIP(screen_buf[baddr]))
baddr = next_unprotected(baddr);
else while (IS_FA(screen_buf[baddr]))
INC_BA(baddr);
cursor_move(baddr);
}
mdt_set(fa);
return True;
}
/*
* Handle an ordinary character key, given an ASCII code.
*/
static void
key_ACharacter(unsigned char c, enum keytype keytype, enum iaction cause)
{
register int i;
struct akeysym ak;
ak.keysym = c;
ak.keytype = keytype;
switch (composing) {
case NONE:
break;
case COMPOSE:
for (i = 0; i < n_composites; i++)
if (ak_eq(composites[i].k1, ak) ||
ak_eq(composites[i].k2, ak))
break;
if (i < n_composites) {
cc_first.keysym = c;
cc_first.keytype = keytype;
composing = FIRST;
status_compose(True, c, keytype);
} else {
ring_bell();
composing = NONE;
status_compose(False, 0, KT_STD);
}
return;
case FIRST:
composing = NONE;
status_compose(False, 0, KT_STD);
for (i = 0; i < n_composites; i++)
if ((ak_eq(composites[i].k1, cc_first) &&
ak_eq(composites[i].k2, ak)) ||
(ak_eq(composites[i].k1, ak) &&
ak_eq(composites[i].k2, cc_first)))
break;
if (i < n_composites) {
c = composites[i].translation.keysym;
keytype = composites[i].translation.keytype;
} else {
ring_bell();
return;
}
break;
}
trace_event(" %s -> Key(\"%s\")\n",
ia_name[(int) cause], ctl_see((int) c));
if (IN_3270) {
if (c < ' ') {
trace_event(" dropped (control char)\n");
return;
}
(void) key_Character((int) asc2cg[c], keytype == KT_GE, False);
}
#if defined(X3270_ANSI) /*[*/
else if (IN_ANSI) {
net_sendc((char) c);
}
#endif /*]*/
else {
trace_event(" dropped (not connected)\n");
}
}
/*
* Simple toggles.
*/
#if defined(X3270_DISPLAY) /*[*/
void
AltCursor_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(AltCursor_action, event, params, num_params);
do_toggle(ALT_CURSOR);
}
#endif /*]*/
void
MonoCase_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(MonoCase_action, event, params, num_params);
do_toggle(MONOCASE);
}
/*
* Flip the display left-to-right
*/
void
Flip_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Flip_action, event, params, num_params);
screen_flip();
}
/*
* Tab forward to next field.
*/
void
Tab_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(Tab_action, event, params, num_params);
if (kybdlock) {
enq_ta(Tab_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_sendc('\t');
return;
}
#endif /*]*/
cursor_move(next_unprotected(cursor_addr));
}
/*
* Tab backward to previous field.
*/
void
BackTab_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
register int baddr, nbaddr;
int sbaddr;
action_debug(BackTab_action, event, params, num_params);
if (kybdlock) {
enq_ta(BackTab_action, CN, CN);
return;
}
if (!IN_3270)
return;
baddr = cursor_addr;
DEC_BA(baddr);
if (IS_FA(screen_buf[baddr])) /* at bof */
DEC_BA(baddr);
sbaddr = baddr;
while (True) {
nbaddr = baddr;
INC_BA(nbaddr);
if (IS_FA(screen_buf[baddr])
&& !FA_IS_PROTECTED(screen_buf[baddr])
&& !IS_FA(screen_buf[nbaddr]))
break;
DEC_BA(baddr);
if (baddr == sbaddr) {
cursor_move(0);
return;
}
}
INC_BA(baddr);
cursor_move(baddr);
}
/*
* Deferred keyboard unlock.
*/
static void
defer_unlock(void)
{
kybdlock_clr(KL_DEFERRED_UNLOCK, "defer_unlock");
status_reset();
if (CONNECTED)
ps_process();
}
/*
* Reset keyboard lock.
*/
void
do_reset(Boolean explicit)
{
/*
* If explicit (from the keyboard) and there is typeahead or
* a half-composed key, simply flush it.
*/
if (explicit
#if defined(X3270_FT) /*[*/
|| ft_state != FT_NONE
#endif /*]*/
) {
Boolean half_reset = False;
if (flush_ta())
half_reset = True;
if (composing != NONE) {
composing = NONE;
status_compose(False, 0, KT_STD);
half_reset = True;
}
if (half_reset)
return;
}
/* Always clear insert mode. */
insert_mode(False);
/* Otherwise, if not connect, reset is a no-op. */
if (!CONNECTED)
return;
/*
* Remove any deferred keyboard unlock. We will either unlock the
* keyboard now, or want to defer further into the future.
*/
if (kybdlock & KL_DEFERRED_UNLOCK)
RemoveTimeOut(unlock_id);
/*
* If explicit (from the keyboard), unlock the keyboard now.
* Otherwise (from the host), schedule a deferred keyboard unlock.
*/
if (explicit) {
kybdlock_clr(-1, "do_reset");
} else if (kybdlock &
(KL_DEFERRED_UNLOCK | KL_OIA_TWAIT | KL_OIA_LOCKED | KL_AWAITING_FIRST)) {
kybdlock_clr(~KL_DEFERRED_UNLOCK, "do_reset");
kybdlock_set(KL_DEFERRED_UNLOCK, "do_reset");
unlock_id = AddTimeOut(UNLOCK_MS, defer_unlock);
}
/* Clean up other modes. */
status_reset();
mcursor_normal();
composing = NONE;
status_compose(False, 0, KT_STD);
}
void
Reset_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Reset_action, event, params, num_params);
do_reset(True);
}
/*
* Move to first unprotected field on screen.
*/
void
Home_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Home_action, event, params, num_params);
if (kybdlock) {
enq_ta(Home_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
ansi_send_home();
return;
}
#endif /*]*/
if (!formatted) {
cursor_move(0);
return;
}
cursor_move(next_unprotected(ROWS*COLS-1));
}
/*
* Cursor left 1 position.
*/
static void
do_left(void)
{
register int baddr;
baddr = cursor_addr;
DEC_BA(baddr);
cursor_move(baddr);
}
void
Left_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Left_action, event, params, num_params);
if (kybdlock) {
enq_ta(Left_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
ansi_send_left();
return;
}
#endif /*]*/
if (!flipped)
do_left();
else {
register int baddr;
baddr = cursor_addr;
INC_BA(baddr);
cursor_move(baddr);
}
}
/*
* Delete char key.
* Returns "True" if succeeds, "False" otherwise.
*/
static Boolean
do_delete(void)
{
register int baddr, end_baddr;
register unsigned char *fa;
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
operator_error(KL_OERR_PROTECTED);
return False;
}
/* find next fa */
end_baddr = baddr;
do {
INC_BA(end_baddr);
if (IS_FA(screen_buf[end_baddr]))
break;
} while (end_baddr != baddr);
DEC_BA(end_baddr);
if (end_baddr > baddr) {
ctlr_bcopy(baddr+1, baddr, end_baddr - baddr, 0);
} else if (end_baddr != baddr) {
ctlr_bcopy(baddr+1, baddr, ((ROWS * COLS) - 1) - baddr, 0);
ctlr_add((ROWS * COLS) - 1, screen_buf[0], 0);
ctlr_bcopy(1, 0, end_baddr, 0);
}
ctlr_add(end_baddr, CG_null, 0);
mdt_set(fa);
return True;
}
void
Delete_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(Delete_action, event, params, num_params);
if (kybdlock) {
enq_ta(Delete_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_sendc('\177');
return;
}
#endif /*]*/
if (!do_delete())
return;
if (reverse) {
int baddr = cursor_addr;
DEC_BA(baddr);
if (!IS_FA(screen_buf[baddr]))
cursor_move(baddr);
}
}
/*
* Backspace.
*/
void
BackSpace_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(BackSpace_action, event, params, num_params);
if (kybdlock) {
enq_ta(BackSpace_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_send_erase();
return;
}
#endif /*]*/
if (reverse)
(void) do_delete();
else if (!flipped)
do_left();
else {
register int baddr;
baddr = cursor_addr;
DEC_BA(baddr);
cursor_move(baddr);
}
}
/*
* Destructive backspace, like Unix "erase".
*/
void
Erase_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
int baddr;
unsigned char *fa;
action_debug(Erase_action, event, params, num_params);
if (kybdlock) {
enq_ta(Erase_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_send_erase();
return;
}
#endif /*]*/
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (fa == &screen_buf[baddr] || FA_IS_PROTECTED(*fa)) {
operator_error(KL_OERR_PROTECTED);
return;
}
if (baddr && fa == &screen_buf[baddr - 1])
return;
do_left();
(void) do_delete();
}
/*
* Cursor right 1 position.
*/
void
Right_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
register int baddr;
action_debug(Right_action, event, params, num_params);
if (kybdlock) {
enq_ta(Right_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
ansi_send_right();
return;
}
#endif /*]*/
if (!flipped) {
baddr = cursor_addr;
INC_BA(baddr);
cursor_move(baddr);
} else
do_left();
}
/*
* Cursor left 2 positions.
*/
void
Left2_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
register int baddr;
action_debug(Left2_action, event, params, num_params);
if (kybdlock) {
enq_ta(Left2_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
baddr = cursor_addr;
DEC_BA(baddr);
DEC_BA(baddr);
cursor_move(baddr);
}
/*
* Cursor to previous word.
*/
void
PreviousWord_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
register int baddr;
int baddr0;
unsigned char c;
Boolean prot;
action_debug(PreviousWord_action, event, params, num_params);
if (kybdlock) {
enq_ta(PreviousWord_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
if (!formatted)
return;
baddr = cursor_addr;
prot = FA_IS_PROTECTED(*get_field_attribute(baddr));
/* Skip to before this word, if in one now. */
if (!prot) {
c = screen_buf[baddr];
while (!IS_FA(c) && c != CG_space && c != CG_null) {
DEC_BA(baddr);
if (baddr == cursor_addr)
return;
c = screen_buf[baddr];
}
}
baddr0 = baddr;
/* Find the end of the preceding word. */
do {
c = screen_buf[baddr];
if (IS_FA(c)) {
DEC_BA(baddr);
prot = FA_IS_PROTECTED(*get_field_attribute(baddr));
continue;
}
if (!prot && c != CG_space && c != CG_null)
break;
DEC_BA(baddr);
} while (baddr != baddr0);
if (baddr == baddr0)
return;
/* Go it its front. */
for (;;) {
DEC_BA(baddr);
c = screen_buf[baddr];
if (IS_FA(c) || c == CG_space || c == CG_null) {
break;
}
}
INC_BA(baddr);
cursor_move(baddr);
}
/*
* Cursor right 2 positions.
*/
void
Right2_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
register int baddr;
action_debug(Right2_action, event, params, num_params);
if (kybdlock) {
enq_ta(Right2_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
baddr = cursor_addr;
INC_BA(baddr);
INC_BA(baddr);
cursor_move(baddr);
}
/* Find the next unprotected word, or -1 */
static int
nu_word(int baddr)
{
int baddr0 = baddr;
unsigned char c;
Boolean prot;
prot = FA_IS_PROTECTED(*get_field_attribute(baddr));
do {
c = screen_buf[baddr];
if (IS_FA(c))
prot = FA_IS_PROTECTED(c);
else if (!prot && c != CG_space && c != CG_null)
return baddr;
INC_BA(baddr);
} while (baddr != baddr0);
return -1;
}
/* Find the next word in this field, or -1 */
static int
nt_word(int baddr)
{
int baddr0 = baddr;
unsigned char c;
Boolean in_word = True;
do {
c = screen_buf[baddr];
if (IS_FA(c))
return -1;
if (in_word) {
if (c == CG_space || c == CG_null)
in_word = False;
} else {
if (c != CG_space && c != CG_null)
return baddr;
}
INC_BA(baddr);
} while (baddr != baddr0);
return -1;
}
/*
* Cursor to next unprotected word.
*/
void
NextWord_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
unsigned char c;
action_debug(NextWord_action, event, params, num_params);
if (kybdlock) {
enq_ta(NextWord_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
if (!formatted)
return;
/* If not in an unprotected field, go to the next unprotected word. */
if (IS_FA(screen_buf[cursor_addr]) ||
FA_IS_PROTECTED(*get_field_attribute(cursor_addr))) {
baddr = nu_word(cursor_addr);
if (baddr != -1)
cursor_move(baddr);
return;
}
/* If there's another word in this field, go to it. */
baddr = nt_word(cursor_addr);
if (baddr != -1) {
cursor_move(baddr);
return;
}
/* If in a word, go to just after its end. */
c = screen_buf[cursor_addr];
if (c != CG_space && c != CG_null) {
baddr = cursor_addr;
do {
c = screen_buf[baddr];
if (c == CG_space || c == CG_null) {
cursor_move(baddr);
return;
} else if (IS_FA(c)) {
baddr = nu_word(baddr);
if (baddr != -1)
cursor_move(baddr);
return;
}
INC_BA(baddr);
} while (baddr != cursor_addr);
}
/* Otherwise, go to the next unprotected word. */
else {
baddr = nu_word(cursor_addr);
if (baddr != -1)
cursor_move(baddr);
}
}
/*
* Cursor up 1 position.
*/
void
Up_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
action_debug(Up_action, event, params, num_params);
if (kybdlock) {
enq_ta(Up_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
ansi_send_up();
return;
}
#endif /*]*/
baddr = cursor_addr - COLS;
if (baddr < 0)
baddr = (cursor_addr + (ROWS * COLS)) - COLS;
cursor_move(baddr);
}
/*
* Cursor down 1 position.
*/
void
Down_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
action_debug(Down_action, event, params, num_params);
if (kybdlock) {
enq_ta(Down_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
ansi_send_down();
return;
}
#endif /*]*/
baddr = (cursor_addr + COLS) % (COLS * ROWS);
cursor_move(baddr);
}
/*
* Cursor to first field on next line or any lines after that.
*/
void
Newline_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
register unsigned char *fa;
action_debug(Newline_action, event, params, num_params);
if (kybdlock) {
enq_ta(Newline_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_sendc('\n');
return;
}
#endif /*]*/
baddr = (cursor_addr + COLS) % (COLS * ROWS); /* down */
baddr = (baddr / COLS) * COLS; /* 1st col */
fa = get_field_attribute(baddr);
if (fa != (&screen_buf[baddr]) && !FA_IS_PROTECTED(*fa))
cursor_move(baddr);
else
cursor_move(next_unprotected(baddr));
}
/*
* DUP key
*/
void
Dup_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(Dup_action, event, params, num_params);
if (kybdlock) {
enq_ta(Dup_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
if (key_Character(CG_dup, False, False))
cursor_move(next_unprotected(cursor_addr));
}
/*
* FM key
*/
void
FieldMark_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(FieldMark_action, event, params, num_params);
if (kybdlock) {
enq_ta(FieldMark_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
(void) key_Character(CG_fm, False, False);
}
/*
* Vanilla AID keys.
*/
void
Enter_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(Enter_action, event, params, num_params);
if (kybdlock & KL_OIA_MINUS)
return;
else if (kybdlock)
enq_ta(Enter_action, CN, CN);
else
key_AID(AID_ENTER);
}
void
SysReq_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(SysReq_action, event, params, num_params);
if (IN_ANSI)
return;
#if defined(X3270_TN3270E) /*[*/
if (IN_E) {
net_abort();
} else
#endif /*]*/
{
if (kybdlock & KL_OIA_MINUS)
return;
else if (kybdlock)
enq_ta(SysReq_action, CN, CN);
else
key_AID(AID_SYSREQ);
}
}
/*
* Clear AID key
*/
void
Clear_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(Clear_action, event, params, num_params);
if (kybdlock & KL_OIA_MINUS)
return;
if (kybdlock && CONNECTED) {
enq_ta(Clear_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
ansi_send_clear();
return;
}
#endif /*]*/
buffer_addr = 0;
ctlr_clear(True);
cursor_move(0);
if (CONNECTED)
key_AID(AID_CLEAR);
}
/*
* Cursor Select key (light pen simulator).
*/
static void
lightpen_select(int baddr)
{
register unsigned char *fa, *sel;
int designator;
fa = get_field_attribute(baddr);
if (!FA_IS_SEL(*fa)) {
ring_bell();
return;
}
sel = fa + 1;
designator = sel - screen_buf;
switch (*sel) {
case CG_greater: /* > */
ctlr_add(designator, CG_question, 0); /* change to ? */
mdt_clear(fa);
break;
case CG_question: /* ? */
ctlr_add(designator, CG_greater, 0); /* change to > */
mdt_set(fa);
break;
case CG_space: /* space */
case CG_null: /* null */
mdt_set(fa);
key_AID(AID_SELECT);
break;
case CG_ampersand: /* & */
mdt_set(fa);
key_AID(AID_ENTER);
break;
default:
ring_bell();
break;
}
}
/*
* Cursor Select key (light pen simulator) -- at the current cursor location.
*/
void
CursorSelect_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(CursorSelect_action, event, params, num_params);
if (kybdlock) {
enq_ta(CursorSelect_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
lightpen_select(cursor_addr);
}
#if defined(X3270_DISPLAY) /*[*/
/*
* Cursor Select mouse action (light pen simulator).
*/
void
MouseSelect_action(Widget w, XEvent *event, String *params,
Cardinal *num_params)
{
action_debug(MouseSelect_action, event, params, num_params);
if (w != *screen)
return;
if (kybdlock)
return;
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
lightpen_select(mouse_baddr(w, event));
}
#endif /*]*/
/*
* Erase End Of Field Key.
*/
void
EraseEOF_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
register unsigned char *fa;
action_debug(EraseEOF_action, event, params, num_params);
if (kybdlock) {
enq_ta(EraseEOF_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
operator_error(KL_OERR_PROTECTED);
return;
}
if (formatted) { /* erase to next field attribute */
do {
ctlr_add(baddr, CG_null, 0);
INC_BA(baddr);
} while (!IS_FA(screen_buf[baddr]));
mdt_set(fa);
} else { /* erase to end of screen */
do {
ctlr_add(baddr, CG_null, 0);
INC_BA(baddr);
} while (baddr != 0);
}
}
/*
* Erase all Input Key.
*/
void
EraseInput_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr, sbaddr;
unsigned char fa;
Boolean f;
action_debug(EraseInput_action, event, params, num_params);
if (kybdlock) {
enq_ta(EraseInput_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
if (formatted) {
/* find first field attribute */
baddr = 0;
do {
if (IS_FA(screen_buf[baddr]))
break;
INC_BA(baddr);
} while (baddr != 0);
sbaddr = baddr;
f = False;
do {
fa = screen_buf[baddr];
if (!FA_IS_PROTECTED(fa)) {
mdt_clear(&screen_buf[baddr]);
do {
INC_BA(baddr);
if (!f) {
cursor_move(baddr);
f = True;
}
if (!IS_FA(screen_buf[baddr])) {
ctlr_add(baddr, CG_null, 0);
}
} while (!IS_FA(screen_buf[baddr]));
} else { /* skip protected */
do {
INC_BA(baddr);
} while (!IS_FA(screen_buf[baddr]));
}
} while (baddr != sbaddr);
if (!f)
cursor_move(0);
} else {
ctlr_clear(True);
cursor_move(0);
}
}
/*
* Delete word key. Backspaces the cursor until it hits the front of a word,
* deletes characters until it hits a blank or null, and deletes all of these
* but the last.
*
* Which is to say, does a ^W.
*/
void
DeleteWord_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr, baddr2, front_baddr, back_baddr, end_baddr;
register unsigned char *fa;
action_debug(DeleteWord_action, event, params, num_params);
if (kybdlock) {
enq_ta(DeleteWord_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_send_werase();
return;
}
#endif /*]*/
if (!formatted)
return;
baddr = cursor_addr;
fa = get_field_attribute(baddr);
/* Make sure we're on a modifiable field. */
if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
operator_error(KL_OERR_PROTECTED);
return;
}
/* Search backwards for a non-blank character. */
front_baddr = baddr;
while (screen_buf[front_baddr] == CG_space ||
screen_buf[front_baddr] == CG_null)
DEC_BA(front_baddr);
/* If we ran into the edge of the field without seeing any non-blanks,
there isn't any word to delete; just move the cursor. */
if (IS_FA(screen_buf[front_baddr])) {
cursor_move(front_baddr+1);
return;
}
/* front_baddr is now pointing at a non-blank character. Now search
for the first blank to the left of that (or the edge of the field),
leaving front_baddr pointing at the the beginning of the word. */
while (!IS_FA(screen_buf[front_baddr]) &&
screen_buf[front_baddr] != CG_space &&
screen_buf[front_baddr] != CG_null)
DEC_BA(front_baddr);
INC_BA(front_baddr);
/* Find the end of the word, searching forward for the edge of the
field or a non-blank. */
back_baddr = front_baddr;
while (!IS_FA(screen_buf[back_baddr]) &&
screen_buf[back_baddr] != CG_space &&
screen_buf[back_baddr] != CG_null)
INC_BA(back_baddr);
/* Find the start of the next word, leaving back_baddr pointing at it
or at the end of the field. */
while (screen_buf[back_baddr] == CG_space ||
screen_buf[back_baddr] == CG_null)
INC_BA(back_baddr);
/* Find the end of the field, leaving end_baddr pointing at the field
attribute of the start of the next field. */
end_baddr = back_baddr;
while (!IS_FA(screen_buf[end_baddr]))
INC_BA(end_baddr);
/* Copy any text to the right of the word we are deleting. */
baddr = front_baddr;
baddr2 = back_baddr;
while (baddr2 != end_baddr) {
ctlr_add(baddr, screen_buf[baddr2], 0);
INC_BA(baddr);
INC_BA(baddr2);
}
/* Insert nulls to pad out the end of the field. */
while (baddr != end_baddr) {
ctlr_add(baddr, CG_null, 0);
INC_BA(baddr);
}
/* Set the MDT and move the cursor. */
mdt_set(fa);
cursor_move(front_baddr);
}
/*
* Delete field key. Similar to EraseEOF, but it wipes out the entire field
* rather than just to the right of the cursor, and it leaves the cursor at
* the front of the field.
*
* Which is to say, does a ^U.
*/
void
DeleteField_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
register unsigned char *fa;
action_debug(DeleteField_action, event, params, num_params);
if (kybdlock) {
enq_ta(DeleteField_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI) {
net_send_kill();
return;
}
#endif /*]*/
if (!formatted)
return;
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
operator_error(KL_OERR_PROTECTED);
return;
}
while (!IS_FA(screen_buf[baddr]))
DEC_BA(baddr);
INC_BA(baddr);
cursor_move(baddr);
while (!IS_FA(screen_buf[baddr])) {
ctlr_add(baddr, CG_null, 0);
INC_BA(baddr);
}
mdt_set(fa);
}
/*
* Set insert mode key.
*/
void
Insert_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(Insert_action, event, params, num_params);
if (kybdlock) {
enq_ta(Insert_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
insert_mode(True);
}
/*
* Toggle insert mode key.
*/
void
ToggleInsert_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(ToggleInsert_action, event, params, num_params);
if (kybdlock) {
enq_ta(ToggleInsert_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
if (insert)
insert_mode(False);
else
insert_mode(True);
}
/*
* Toggle reverse mode key.
*/
void
ToggleReverse_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(ToggleReverse_action, event, params, num_params);
if (kybdlock) {
enq_ta(ToggleReverse_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
reverse_mode(!reverse);
}
/*
* Move the cursor to the first blank after the last nonblank in the
* field, or if the field is full, to the last character in the field.
*/
void
FieldEnd_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
int baddr;
unsigned char *fa, c;
int last_nonblank = -1;
action_debug(FieldEnd_action, event, params, num_params);
if (kybdlock) {
enq_ta(FieldEnd_action, CN, CN);
return;
}
#if defined(X3270_ANSI) /*[*/
if (IN_ANSI)
return;
#endif /*]*/
if (!formatted)
return;
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (fa == &screen_buf[baddr] || FA_IS_PROTECTED(*fa))
return;
baddr = fa - screen_buf;
while (True) {
INC_BA(baddr);
c = screen_buf[baddr];
if (IS_FA(c))
break;
if (c != CG_null && c != CG_space)
last_nonblank = baddr;
}
if (last_nonblank == -1) {
baddr = fa - screen_buf;
INC_BA(baddr);
} else {
baddr = last_nonblank;
INC_BA(baddr);
if (IS_FA(screen_buf[baddr]))
baddr = last_nonblank;
}
cursor_move(baddr);
}
/*
* MoveCursor action. Depending on arguments, this is either a move to the
* mouse cursor position, or to an absolute location.
*/
void
MoveCursor_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
register int baddr;
int row, col;
action_debug(MoveCursor_action, event, params, num_params);
if (kybdlock) {
if (*num_params == 2)
enq_ta(MoveCursor_action, params[0], params[1]);
return;
}
switch (*num_params) {
#if defined(X3270_DISPLAY) /*[*/
case 0: /* mouse click, presumably */
if (w != *screen)
return;
cursor_move(mouse_baddr(w, event));
break;
#endif /*]*/
case 2: /* probably a macro call */
row = atoi(params[0]);
col = atoi(params[1]);
if (!IN_3270) {
row--;
col--;
}
if (row < 0)
row = 0;
if (col < 0)
col = 0;
baddr = ((row * COLS) + col) % (ROWS * COLS);
cursor_move(baddr);
break;
default: /* couln't say */
popup_an_error("%s requires 0 or 2 arguments",
action_name(MoveCursor_action));
break;
}
}
/*
* Key action.
*/
void
Key_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
Cardinal i;
KeySym k;
enum keytype keytype;
action_debug(Key_action, event, params, num_params);
for (i = 0; i < *num_params; i++) {
char *s = params[i];
k = MyStringToKeysym(s, &keytype);
if (k == NoSymbol) {
popup_an_error("%s: Nonexistent or invalid KeySym: %s",
action_name(Key_action), s);
continue;
}
if (k & ~0xff) {
popup_an_error("%s: Invalid KeySym: %s",
action_name(Key_action), s);
continue;
}
key_ACharacter((unsigned char)(k & 0xff), keytype, IA_KEY);
}
}
/*
* String action.
*/
void
String_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
Cardinal i;
int len = 0;
char *s;
action_debug(String_action, event, params, num_params);
/* Determine the total length of the strings. */
for (i = 0; i < *num_params; i++)
len += strlen(params[i]);
if (!len)
return;
/* Allocate a block of memory and copy them in. */
s = Malloc(len + 1);
*s = '\0';
for (i = 0; i < *num_params; i++)
(void) strcat(s, params[i]);
/* Set a pending string. */
ps_set(s, False);
}
/*
* HexString action.
*/
void
HexString_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
Cardinal i;
int len = 0;
char *s;
char *t;
action_debug(HexString_action, event, params, num_params);
/* Determine the total length of the strings. */
for (i = 0; i < *num_params; i++) {
t = params[i];
if (!strncmp(t, "0x", 2) || !strncmp(t, "0X", 2))
t += 2;
len += strlen(t);
}
if (!len)
return;
/* Allocate a block of memory and copy them in. */
s = Malloc(len + 1);
*s = '\0';
for (i = 0; i < *num_params; i++) {
t = params[i];
if (!strncmp(t, "0x", 2) || !strncmp(t, "0X", 2))
t += 2;
(void) strcat(s, t);
}
/* Set a pending string. */
ps_set(s, True);
}
/*
* Dual-mode action for the "asciicircum" ("^") key:
* If in ANSI mode, pass through untranslated.
* If in 3270 mode, translate to "notsign".
*/
void
CircumNot_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(CircumNot_action, event, params, num_params);
if (IN_3270 && composing == NONE)
key_ACharacter(0xac, KT_STD, IA_KEY);
else
key_ACharacter('^', KT_STD, IA_KEY);
}
/* PA key action for String actions */
static void
do_pa(unsigned n)
{
if (n < 1 || n > PA_SZ) {
popup_an_error("Unknown PA key %d", n);
return;
}
if (kybdlock) {
char nn[3];
(void) sprintf(nn, "%d", n);
enq_ta(PA_action, nn, CN);
return;
}
key_AID(pa_xlate[n-1]);
}
/* PF key action for String actions */
static void
do_pf(unsigned n)
{
if (n < 1 || n > PF_SZ) {
popup_an_error("Unknown PF key %d", n);
return;
}
if (kybdlock) {
char nn[3];
(void) sprintf(nn, "%d", n);
enq_ta(PF_action, nn, CN);
return;
}
key_AID(pf_xlate[n-1]);
}
/*
* Set or clear the keyboard scroll lock.
*/
void
kybd_scroll_lock(Boolean lock)
{
if (!IN_3270)
return;
if (lock)
kybdlock_set(KL_SCROLLED, "kybd_scroll_lock");
else
kybdlock_clr(KL_SCROLLED, "kybd_scroll_lock");
}
/*
* Move the cursor back within the legal paste area.
* Returns a Boolean indicating success.
*/
static Boolean
remargin(int lmargin)
{
Boolean ever = False;
int baddr, b0 = 0;
unsigned char *fa;
baddr = cursor_addr;
while (BA_TO_COL(baddr) < lmargin) {
baddr = ROWCOL_TO_BA(BA_TO_ROW(baddr), lmargin);
if (!ever) {
b0 = baddr;
ever = True;
}
fa = get_field_attribute(baddr);
if (fa == &screen_buf[baddr] || FA_IS_PROTECTED(*fa)) {
baddr = next_unprotected(baddr);
if (baddr <= b0)
return False;
}
}
cursor_move(baddr);
return True;
}
/*
* Pretend that a sequence of keys was entered at the keyboard.
*
* "Pasting" means that the sequence came from the X clipboard. Returns are
* ignored; newlines mean "move to beginning of next line"; tabs and formfeeds
* become spaces. Backslashes are not special, but ASCII ESC characters are
* used to signify 3270 Graphic Escapes.
*
* "Not pasting" means that the sequence is a login string specified in the
* hosts file, or a parameter to the String action. Returns are "move to
* beginning of next line"; newlines mean "Enter AID" and the termination of
* processing the string. Backslashes are processed as in C.
*
* Returns the number of unprocessed characters.
*/
int
emulate_input(char *s, int len, Boolean pasting)
{
char c;
enum { BASE, BACKSLASH, BACKX, BACKP, BACKPA, BACKPF, OCTAL, HEX,
XGE } state = BASE;
int literal = 0;
int nc = 0;
enum iaction ia = pasting ? IA_PASTE : IA_STRING;
int orig_addr = cursor_addr;
int orig_col = BA_TO_COL(cursor_addr);
/*
* In the switch statements below, "break" generally means "consume
* this character," while "continue" means "rescan this character."
*/
while (len) {
/*
* It isn't possible to unlock the keyboard from a string,
* so if the keyboard is locked, it's fatal
*/
if (kybdlock) {
trace_event(" keyboard locked, string dropped\n");
return 0;
}
if (pasting && IN_3270) {
/* Check for cursor wrap to top of screen. */
if (cursor_addr < orig_addr)
return len-1; /* wrapped */
/* Jump cursor over left margin. */
if (toggled(MARGINED_PASTE) &&
BA_TO_COL(cursor_addr) < orig_col) {
if (!remargin(orig_col))
return len-1;
}
}
c = *s;
switch (state) {
case BASE:
switch (c) {
case '\b':
action_internal(Left_action, ia, CN, CN);
continue;
case '\f':
if (pasting) {
key_ACharacter((unsigned char) ' ',
KT_STD, ia);
} else {
action_internal(Clear_action, ia, CN, CN);
if (IN_3270)
return len-1;
else
break;
}
case '\n':
if (pasting)
action_internal(Newline_action, ia, CN, CN);
else {
action_internal(Enter_action, ia, CN, CN);
if (IN_3270)
return len-1;
}
break;
case '\r': /* ignored */
break;
case '\t':
action_internal(Tab_action, ia, CN, CN);
break;
case '\\': /* backslashes are NOT special when pasting */
if (!pasting)
state = BACKSLASH;
else
key_ACharacter((unsigned char) c,
KT_STD, ia);
break;
case '\033': /* ESC is special only when pasting */
if (pasting)
state = XGE;
break;
case '[': /* APL left bracket */
if (pasting && appres.apl_mode)
key_ACharacter(
(unsigned char) XK_Yacute,
KT_GE, ia);
else
key_ACharacter((unsigned char) c,
KT_STD, ia);
break;
case ']': /* APL right bracket */
if (pasting && appres.apl_mode)
key_ACharacter(
(unsigned char) XK_diaeresis,
KT_GE, ia);
else
key_ACharacter((unsigned char) c,
KT_STD, ia);
break;
default:
key_ACharacter((unsigned char) c, KT_STD,
ia);
break;
}
break;
case BACKSLASH: /* last character was a backslash */
switch (c) {
case 'a':
popup_an_error("%s: Bell not supported",
action_name(String_action));
state = BASE;
break;
case 'b':
action_internal(Left_action, ia, CN, CN);
state = BASE;
break;
case 'f':
action_internal(Clear_action, ia, CN, CN);
state = BASE;
if (IN_3270)
return len-1;
else
break;
case 'n':
action_internal(Enter_action, ia, CN, CN);
state = BASE;
if (IN_3270)
return len-1;
else
break;
case 'p':
state = BACKP;
break;
case 'r':
action_internal(Newline_action, ia, CN, CN);
state = BASE;
break;
case 't':
action_internal(Tab_action, ia, CN, CN);
state = BASE;
break;
case 'v':
popup_an_error("%s: Vertical tab not supported",
action_name(String_action));
state = BASE;
break;
case 'x':
state = BACKX;
break;
case '\\':
key_ACharacter((unsigned char) c, KT_STD, ia);
state = BASE;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
state = OCTAL;
literal = 0;
nc = 0;
continue;
default:
state = BASE;
continue;
}
break;
case BACKP: /* last two characters were "\p" */
switch (c) {
case 'a':
literal = 0;
nc = 0;
state = BACKPA;
break;
case 'f':
literal = 0;
nc = 0;
state = BACKPF;
break;
default:
popup_an_error("%s: Unknown character after \\p",
action_name(String_action));
state = BASE;
break;
}
break;
case BACKPF: /* last three characters were "\pf" */
if (nc < 2 && isdigit(c)) {
literal = (literal * 10) + (c - '0');
nc++;
} else if (!nc) {
popup_an_error("%s: Unknown character after \\pf",
action_name(String_action));
state = BASE;
} else {
do_pf(literal);
if (IN_3270)
return len-1;
state = BASE;
continue;
}
break;
case BACKPA: /* last three characters were "\pa" */
if (nc < 1 && isdigit(c)) {
literal = (literal * 10) + (c - '0');
nc++;
} else if (!nc) {
popup_an_error("%s: Unknown character after \\pa",
action_name(String_action));
state = BASE;
} else {
do_pa(literal);
if (IN_3270)
return len-1;
state = BASE;
continue;
}
break;
case BACKX: /* last two characters were "\x" */
if (isxdigit(c)) {
state = HEX;
literal = 0;
nc = 0;
continue;
} else {
popup_an_error("%s: Missing hex digits after \\x",
action_name(String_action));
state = BASE;
continue;
}
case OCTAL: /* have seen \ and one or more octal digits */
if (nc < 3 && isdigit(c) && c < '8') {
literal = (literal * 8) + FROM_HEX(c);
nc++;
break;
} else {
key_ACharacter((unsigned char) literal, KT_STD,
ia);
state = BASE;
continue;
}
case HEX: /* have seen \ and one or more hex digits */
if (nc < 2 && isxdigit(c)) {
literal = (literal * 16) + FROM_HEX(c);
nc++;
break;
} else {
key_ACharacter((unsigned char) literal, KT_STD,
ia);
state = BASE;
continue;
}
case XGE: /* have seen ESC */
switch (c) {
case ';': /* FM */
key_Character(CG_fm, False, True);
break;
case '*': /* DUP */
key_Character(CG_dup, False, True);
break;
default:
key_ACharacter((unsigned char) c, KT_GE, ia);
break;
}
state = BASE;
break;
}
s++;
len--;
}
switch (state) {
case OCTAL:
case HEX:
key_ACharacter((unsigned char) literal, KT_STD, ia);
state = BASE;
break;
case BACKPF:
if (nc > 0) {
do_pf(literal);
state = BASE;
}
break;
case BACKPA:
if (nc > 0) {
do_pa(literal);
state = BASE;
}
break;
default:
break;
}
if (state != BASE)
popup_an_error("%s: Missing data after \\",
action_name(String_action));
return len;
}
/*
* Pretend that a sequence of hexadecimal characters was entered at the
* keyboard. The input is a sequence of hexadecimal bytes, 2 characters
* per byte. If connected in ANSI mode, these are treated as ASCII
* characters; if in 3270 mode, they are considered EBCDIC.
*
* Graphic Escapes are handled as \E.
*/
void
hex_input(char *s)
{
char *t;
Boolean escaped;
#if defined(X3270_ANSI) /*[*/
unsigned char *xbuf = (unsigned char *)NULL;
unsigned char *tbuf = (unsigned char *)NULL;
int nbytes = 0;
#endif /*]*/
/* Validate the string. */
if (strlen(s) % 2) {
popup_an_error("%s: Odd number of characters in specification",
action_name(HexString_action));
return;
}
t = s;
escaped = False;
while (*t) {
if (isxdigit(*t) && isxdigit(*(t + 1))) {
escaped = False;
#if defined(X3270_ANSI) /*[*/
nbytes++;
#endif /*]*/
} else if (!strncmp(t, "\\E", 2) || !strncmp(t, "\\e", 2)) {
if (escaped) {
popup_an_error("%s: Double \\E",
action_name(HexString_action));
return;
}
if (!IN_3270) {
popup_an_error("%s: \\E in ANSI mode",
action_name(HexString_action));
return;
}
escaped = True;
} else {
popup_an_error("%s: Illegal character in specification",
action_name(HexString_action));
return;
}
t += 2;
}
if (escaped) {
popup_an_error("%s: Nothing follows \\E",
action_name(HexString_action));
return;
}
#if defined(X3270_ANSI) /*[*/
/* Allocate a temporary buffer. */
if (!IN_3270 && nbytes)
tbuf = xbuf = (unsigned char *)Malloc(nbytes);
#endif /*]*/
/* Pump it in. */
t = s;
escaped = False;
while (*t) {
if (isxdigit(*t) && isxdigit(*(t + 1))) {
unsigned c;
c = (FROM_HEX(*t) * 16) + FROM_HEX(*(t + 1));
if (IN_3270)
key_Character(ebc2cg[c], escaped, True);
#if defined(X3270_ANSI) /*[*/
else
*tbuf++ = (unsigned char)c;
#endif /*]*/
escaped = False;
} else if (!strncmp(t, "\\E", 2) || !strncmp(t, "\\e", 2)) {
escaped = True;
}
t += 2;
}
#if defined(X3270_ANSI) /*[*/
if (!IN_3270 && nbytes) {
net_hexansi_out(xbuf, nbytes);
Free(xbuf);
}
#endif /*]*/
}
void
ignore_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(ignore_action, event, params, num_params);
}
#if defined(X3270_FT) /*[*/
/*
* Set up the cursor and input field for command input.
* Returns the length of the input field, or 0 if there is no field
* to set up.
*/
int
kybd_prime(void)
{
int baddr;
register unsigned char *fa;
int len = 0;
/*
* No point in trying if the screen isn't formatted, the keyboard
* is locked, or we aren't in 3270 mode.
*/
if (!formatted || kybdlock || !IN_3270)
return 0;
fa = get_field_attribute(cursor_addr);
if (IS_FA(screen_buf[cursor_addr]) || FA_IS_PROTECTED(*fa)) {
/*
* The cursor is not in an unprotected field. Find the
* next one.
*/
baddr = next_unprotected(cursor_addr);
/* If there isn't any, give up. */
if (!baddr)
return 0;
/* Move the cursor there. */
} else {
/* Already in an unprotected field. Find its start. */
baddr = cursor_addr;
while (!IS_FA(screen_buf[baddr])) {
DEC_BA(baddr);
}
INC_BA(baddr);
}
/* Move the cursor to the beginning of the field. */
cursor_move(baddr);
/* Erase it. */
while (!IS_FA(screen_buf[baddr])) {
ctlr_add(baddr, 0, 0);
len++;
INC_BA(baddr);
}
/* Return the field length. */
return len;
}
#endif /*]*/
/*
* Translate a keysym name to a keysym, including APL and extended
* characters.
*/
static KeySym
MyStringToKeysym(char *s, enum keytype *keytypep)
{
KeySym k;
int cc;
char *ptr;
#if defined(X3270_APL) /*[*/
if (!strncmp(s, "apl_", 4)) {
int is_ge;
k = APLStringToKeysym(s, &is_ge);
if (is_ge)
*keytypep = KT_GE;
else
*keytypep = KT_STD;
} else
#endif /*]*/
{
k = StringToKeysym(s);
*keytypep = KT_STD;
}
if (k == NoSymbol && strlen(s) == 1)
k = s[0] & 0xff;
if (k < ' ')
k = NoSymbol;
else if (k > 0xff) {
int i;
for (i = 0; i < nxk; i++)
if (xk[i].key == k) {
k = xk[i].assoc;
break;
}
if (k > 0xff)
k = NoSymbol;
}
/* Allow arbitrary values, e.g., 0x03 for ^C. */
if (k == NoSymbol &&
(cc = strtoul(s, &ptr, 0)) > 0 &&
cc < 0xff &&
ptr != s &&
*ptr == '\0')
k = cc;
return k;
}
/* Add a key to the extended association table. */
void
add_xk(KeySym key, KeySym assoc)
{
int i;
for (i = 0; i < nxk; i++)
if (xk[i].key == key) {
xk[i].assoc = assoc;
return;
}
xk = (struct xks *)Realloc(xk, (nxk + 1) * sizeof(struct xks));
xk[nxk].key = key;
xk[nxk].assoc = assoc;
nxk++;
}
/* Clear the extended association table. */
void
clear_xks(void)
{
if (nxk) {
Free(xk);
xk = (struct xks *)NULL;
nxk = 0;
}
}
/*
* FieldExit for the 5250-like emulation.
* Erases from the current cursor position to the end of the field, and moves
* the cursor to the beginning of the next field.
*
* Derived from work (C) Minolta (Schweiz) AG, Beat Rubischon <bru@minolta.ch>
*/
void
FieldExit_action(Widget w unused, XEvent *event, String *params,
Cardinal *num_params)
{
register int baddr;
register unsigned char *fa;
action_debug(FieldExit_action, event, params, num_params);
if (IN_ANSI) {
net_sendc('\n');
return;
}
if (kybdlock) {
enq_ta(FieldExit_action, CN, CN);
return;
}
baddr = cursor_addr;
fa = get_field_attribute(baddr);
if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
operator_error(KL_OERR_PROTECTED);
return;
}
if (formatted) { /* erase to next field attribute */
do {
ctlr_add(baddr, CG_null, 0);
INC_BA(baddr);
} while (!IS_FA(screen_buf[baddr]));
mdt_set(fa);
cursor_move(next_unprotected(cursor_addr));
} else { /* erase to end of screen */
do {
ctlr_add(baddr, CG_null, 0);
INC_BA(baddr);
} while (baddr != 0);
}
}
#if defined(X3270_DISPLAY) /*[*/
/*
* X-dependent code starts here.
*/
/*
* Translate a keymap (from an XQueryKeymap or a KeymapNotify event) into
* a bitmap of Shift, Meta or Alt keys pressed.
*/
#define key_is_down(kc, bitmap) (kc && ((bitmap)[(kc)/8] & (1<<((kc)%8))))
int
state_from_keymap(char keymap[32])
{
static Boolean initted = False;
static KeyCode kc_Shift_L, kc_Shift_R;
static KeyCode kc_Meta_L, kc_Meta_R;
static KeyCode kc_Alt_L, kc_Alt_R;
int pseudo_state = 0;
if (!initted) {
kc_Shift_L = XKeysymToKeycode(display, XK_Shift_L);
kc_Shift_R = XKeysymToKeycode(display, XK_Shift_R);
kc_Meta_L = XKeysymToKeycode(display, XK_Meta_L);
kc_Meta_R = XKeysymToKeycode(display, XK_Meta_R);
kc_Alt_L = XKeysymToKeycode(display, XK_Alt_L);
kc_Alt_R = XKeysymToKeycode(display, XK_Alt_R);
initted = True;
}
if (key_is_down(kc_Shift_L, keymap) ||
key_is_down(kc_Shift_R, keymap))
pseudo_state |= ShiftKeyDown;
if (key_is_down(kc_Meta_L, keymap) ||
key_is_down(kc_Meta_R, keymap))
pseudo_state |= MetaKeyDown;
if (key_is_down(kc_Alt_L, keymap) ||
key_is_down(kc_Alt_R, keymap))
pseudo_state |= AltKeyDown;
return pseudo_state;
}
#undef key_is_down
/*
* Process shift keyboard events. The code has to look for the raw Shift keys,
* rather than using the handy "state" field in the event structure. This is
* because the event state is the state _before_ the key was pressed or
* released. This isn't enough information to distinguish between "left
* shift released" and "left shift released, right shift still held down"
* events, for example.
*
* This function is also called as part of Focus event processing.
*/
void
PA_Shift_action(Widget w unused, XEvent *event unused, String *params unused,
Cardinal *num_params unused)
{
char keys[32];
#if defined(INTERNAL_ACTION_DEBUG) /*[*/
action_debug(PA_Shift_action, event, params, num_params);
#endif /*]*/
XQueryKeymap(display, keys);
shift_event(state_from_keymap(keys));
}
#endif /*]*/
#if defined(X3270_DISPLAY) || defined(C3270) /*[*/
static Boolean
build_composites(void)
{
char *cname;
char *c, *c0, *c1;
char *ln;
char ksname[3][64];
char junk[2];
KeySym k[3];
enum keytype a[3];
int i;
struct composite *cp;
if (appres.compose_map == CN) {
xs_warning("%s: No %s defined", action_name(Compose_action),
ResComposeMap);
return False;
}
cname = xs_buffer("%s.%s", ResComposeMap, appres.compose_map);
if ((c0 = get_resource(cname)) == CN) {
xs_warning("%s: Cannot find %s \"%s\"",
action_name(Compose_action), ResComposeMap,
appres.compose_map);
return False;
}
Free(cname);
c1 = c = NewString(c0); /* will be modified by strtok */
while ((ln = strtok(c, "\n"))) {
Boolean okay = True;
c = NULL;
if (sscanf(ln, " %63[^+ \t] + %63[^= \t] =%63s%1s",
ksname[0], ksname[1], ksname[2], junk) != 3) {
xs_warning("%s: Invalid syntax: %s",
action_name(Compose_action), ln);
continue;
}
for (i = 0; i < 3; i++) {
k[i] = MyStringToKeysym(ksname[i], &a[i]);
if (k[i] == NoSymbol) {
xs_warning("%s: Invalid KeySym: \"%s\"",
action_name(Compose_action), ksname[i]);
okay = False;
break;
}
}
if (!okay)
continue;
composites = (struct composite *) Realloc((char *)composites,
(n_composites + 1) * sizeof(struct composite));
cp = composites + n_composites;
cp->k1.keysym = k[0];
cp->k1.keytype = a[0];
cp->k2.keysym = k[1];
cp->k2.keytype = a[1];
cp->translation.keysym = k[2];
cp->translation.keytype = a[2];
n_composites++;
}
Free(c1);
return True;
}
/*
* Called by the toolkit when the "Compose" key is pressed. "Compose" is
* implemented by pressing and releasing three keys: "Compose" and two
* data keys. For example, "Compose" "s" "s" gives the German "ssharp"
* character, and "Compose" "C", "," gives a capital "C" with a cedilla
* (symbol Ccedilla).
*
* The mechanism breaks down a little when the user presses "Compose" and
* then a non-data key. Oh well.
*/
void
Compose_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(Compose_action, event, params, num_params);
if (!composites && !build_composites())
return;
if (composing == NONE) {
composing = COMPOSE;
status_compose(True, 0, KT_STD);
}
}
#endif /*]*/
#if defined(X3270_DISPLAY) /*[*/
/*
* Called by the toolkit for any key without special actions.
*/
void
Default_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
XKeyEvent *kevent = (XKeyEvent *)event;
char buf[32];
KeySym ks;
int ll;
action_debug(Default_action, event, params, num_params);
switch (event->type) {
case KeyPress:
ll = XLookupString(kevent, buf, 32, &ks, (XComposeStatus *) 0);
if (ll == 1) {
/* Remap certain control characters. */
switch (buf[0]) {
case '\t':
action_internal(Tab_action, IA_DEFAULT, CN, CN);
break;
case '\177':
action_internal(Delete_action, IA_DEFAULT, CN,
CN);
break;
case '\b':
action_internal(BackSpace_action, IA_DEFAULT,
CN, CN);
break;
case '\r':
action_internal(Enter_action, IA_DEFAULT, CN,
CN);
break;
case '\n':
action_internal(Newline_action, IA_DEFAULT, CN,
CN);
break;
default:
key_ACharacter((unsigned char) buf[0], KT_STD,
IA_DEFAULT);
}
return;
}
/* Pick some other reasonable defaults. */
switch (ks) {
case XK_Up:
action_internal(Up_action, IA_DEFAULT, CN, CN);
break;
case XK_Down:
action_internal(Down_action, IA_DEFAULT, CN, CN);
break;
case XK_Left:
action_internal(Left_action, IA_DEFAULT, CN, CN);
break;
case XK_Right:
action_internal(Right_action, IA_DEFAULT, CN, CN);
break;
case XK_Insert:
#if defined(XK_KP_Insert) /*[*/
case XK_KP_Insert:
#endif /*]*/
action_internal(Insert_action, IA_DEFAULT, CN, CN);
break;
case XK_Delete:
action_internal(Delete_action, IA_DEFAULT, CN, CN);
break;
case XK_Home:
action_internal(Home_action, IA_DEFAULT, CN, CN);
break;
case XK_Tab:
action_internal(Tab_action, IA_DEFAULT, CN, CN);
break;
case XK_Clear:
action_internal(Clear_action, IA_DEFAULT, CN, CN);
break;
case XK_Sys_Req:
action_internal(SysReq_action, IA_DEFAULT, CN, CN);
break;
#if defined(XK_3270_Duplicate) /*[*/
/* Funky 3270 keysyms. */
case XK_3270_Duplicate:
action_internal(Dup_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_FieldMark:
action_internal(FieldMark_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_Right2:
action_internal(Right2_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_Left2:
action_internal(Left2_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_BackTab:
action_internal(BackTab_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_EraseEOF:
action_internal(EraseEOF_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_EraseInput:
action_internal(EraseInput_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_Reset:
action_internal(Reset_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_PA1:
action_internal(PA_action, IA_DEFAULT, "1", CN);
break;
case XK_3270_PA2:
action_internal(PA_action, IA_DEFAULT, "2", CN);
break;
case XK_3270_PA3:
action_internal(PA_action, IA_DEFAULT, "3", CN);
break;
case XK_3270_Attn:
action_internal(Attn_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_AltCursor:
action_internal(AltCursor_action, IA_DEFAULT, CN, CN);
break;
case XK_3270_CursorSelect:
action_internal(CursorSelect_action, IA_DEFAULT, CN,
CN);
break;
case XK_3270_Enter:
action_internal(Enter_action, IA_DEFAULT, CN, CN);
break;
#endif /*]*/
#if defined(X3270_APL) /*[*/
/* Funky APL keysyms. */
case XK_downcaret:
action_internal(Key_action, IA_DEFAULT, "apl_downcaret",
CN);
break;
case XK_upcaret:
action_internal(Key_action, IA_DEFAULT, "apl_upcaret",
CN);
break;
case XK_overbar:
action_internal(Key_action, IA_DEFAULT, "apl_overbar",
CN);
break;
case XK_downtack:
action_internal(Key_action, IA_DEFAULT, "apl_downtack",
CN);
break;
case XK_upshoe:
action_internal(Key_action, IA_DEFAULT, "apl_upshoe",
CN);
break;
case XK_downstile:
action_internal(Key_action, IA_DEFAULT, "apl_downstile",
CN);
break;
case XK_underbar:
action_internal(Key_action, IA_DEFAULT, "apl_underbar",
CN);
break;
case XK_jot:
action_internal(Key_action, IA_DEFAULT, "apl_jot", CN);
break;
case XK_quad:
action_internal(Key_action, IA_DEFAULT, "apl_quad", CN);
break;
case XK_uptack:
action_internal(Key_action, IA_DEFAULT, "apl_uptack",
CN);
break;
case XK_circle:
action_internal(Key_action, IA_DEFAULT, "apl_circle",
CN);
break;
case XK_upstile:
action_internal(Key_action, IA_DEFAULT, "apl_upstile",
CN);
break;
case XK_downshoe:
action_internal(Key_action, IA_DEFAULT, "apl_downshoe",
CN);
break;
case XK_rightshoe:
action_internal(Key_action, IA_DEFAULT, "apl_rightshoe",
CN);
break;
case XK_leftshoe:
action_internal(Key_action, IA_DEFAULT, "apl_leftshoe",
CN);
break;
case XK_lefttack:
action_internal(Key_action, IA_DEFAULT, "apl_lefttack",
CN);
break;
case XK_righttack:
action_internal(Key_action, IA_DEFAULT, "apl_righttack",
CN);
break;
#endif /*]*/
default:
if (ks >= XK_F1 && ks <= XK_F24) {
(void) sprintf(buf, "%ld", ks - XK_F1 + 1);
action_internal(PF_action, IA_DEFAULT, buf, CN);
} else
trace_event(" %s: dropped (unknown keysym)\n",
action_name(Default_action));
break;
}
break;
case ButtonPress:
case ButtonRelease:
trace_event(" %s: dropped (no action configured)\n",
action_name(Default_action));
break;
default:
trace_event(" %s: dropped (unknown event type)\n",
action_name(Default_action));
break;
}
}
/*
* Set or clear a temporary keymap.
*
* TemporaryKeymap(x) toggle keymap "x" (add "x" to the keymap, or if
* "x" was already added, remove it)
* TemporaryKeymap() removes the previous keymap, if any
* TemporaryKeymap(None) removes the previous keymap, if any
*/
void
TemporaryKeymap_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
{
action_debug(TemporaryKeymap_action, event, params, num_params);
if (check_usage(TemporaryKeymap_action, *num_params, 0, 1) < 0)
return;
if (*num_params == 0 || !strcmp(params[0], "None")) {
(void) temporary_keymap(CN);
return;
}
if (temporary_keymap(params[0]) < 0)
popup_an_error("%s: Can't find %s %s",
action_name(TemporaryKeymap_action), ResKeymap, params[0]);
}
#endif /*]*/